package com.xishu.service;

import com.xishu.bo.RowAndColumn;
import com.xishu.config.Constant;
import com.xishu.entity.oplog.OrderOpLog;
import com.xishu.entity.order.Order;
import com.xishu.entity.shop.FoodTable;
import com.xishu.entity.shop.FoodTableConfig;
import com.xishu.entity.shop.Scene;
import com.xishu.entity.shop.Shop;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.order.create.CreateOrderChain;
import com.xishu.service.order.base.OrderService;
import com.xishu.util.ClassUtil;
import com.xishu.util.DateUtil;
import com.xishu.util.Tools;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;

public class FoodTableService implements Tools {
    private static Logger logger = LoggerFactory.getLogger(FoodTableService.class);
    public static final String DOLA_FOOD_TABLE_NO = "/dola/foodTableNo/";

    private static FoodTableService instance = new FoodTableService();
    private CommonService commonService = CommonService.getInstance();
    private ShopService shopService = ShopService.getInstance();

    private FoodTableService() {
    }

    public static FoodTableService getInstance() {
        if (instance == null) {
            instance = new FoodTableService();
        }
        return instance;
    }

    public FoodTable findTableById(Long id) {
        FoodTable foodTable = new FoodTable();
        foodTable.setId(id);
        return commonService.searchOne(foodTable);
    }

    /**
     * @param reqFoodTable
     * @return
     * @throws ResponseStatusException
     */
    public FoodTable addOrTogether(FoodTable reqFoodTable, Order order) throws Exception {
        VerifyUtil.verify(() -> reqFoodTable.getShopId() != null);
        VerifyUtil.verify(() -> reqFoodTable.getRow() != null);
        VerifyUtil.verify(() -> reqFoodTable.getColumn() != null);
        VerifyUtil.verify(() -> reqFoodTable.getSceneId() != null);
        Long sceneId = reqFoodTable.getSceneId();
        Long shopId = reqFoodTable.getShopId();

        //餐桌一定要存在
        FoodTableService foodTableService = FoodTableService.getInstance();
        List<FoodTable> foodTableList = foodTableService.findFoodTable(reqFoodTable.getShopId(), reqFoodTable.getRow(), reqFoodTable.getColumn(), sceneId, true);
        VerifyUtil.verify(() -> isNotEmpty(foodTableList), ResponseStatus.FOOD_TABLE_NOT_EXIST);
        Optional<FoodTable> foodTableOptional = foodTableList.stream().filter(p -> getBoolean(p.getEntity())).findAny();
        VerifyUtil.verify(() -> foodTableOptional.isPresent(), ResponseStatus.FOOD_TABLE_NOT_EXIST);
        FoodTable foodTableTemplate = foodTableOptional.get();

        //下面是拼桌操作
        Integer uniqueCode = null;

        if (order == null) {
            //拼桌
            uniqueCode = FoodTableService.getInstance().openFoodTable(reqFoodTable.getShopId());
        } else {
            //移桌
            uniqueCode = order.getUniqueCode();

            //转台日志
            OrderOpLogService kitchenOrderOpLogService = OrderOpLogService.getInstance();
            OrderOpLog kitchenOrderOpLog = kitchenOrderOpLogService.content(order, MOVE_FOOD_TABLE);
            kitchenOrderOpLogService.moveFoodTable(order, foodTableTemplate, kitchenOrderOpLog);

        }

        reqFoodTable.setTemplate(false);
        reqFoodTable.setUniqueCode(uniqueCode);
        reqFoodTable.setStatus(Constant.FOOD_TABLE_STATUS_EATING);
        reqFoodTable.setSceneId(foodTableTemplate.getSceneId());
        reqFoodTable.setCode(foodTableTemplate.getCode());
        Integer showNo = createFoodTableNo(shopId, reqFoodTable.getRow(), reqFoodTable.getColumn(), reqFoodTable.getSceneId());
        logger.info("the foodTableNo is {}", showNo);
        reqFoodTable.setShowNo(showNo);

        CommonService.getInstance().createObject(reqFoodTable);
        //同步餐桌状态
        syncCreateFoodTable(reqFoodTable);
        //创建订单，默认需要创建订单，如果是移桌，那么不用创建订单
        if (order == null) {
            //拼桌
            createOrderAfterCreateTable(reqFoodTable, foodTableTemplate);
        }

        return reqFoodTable;
    }

    /**
     * 创建餐桌之后，同步创建订单
     *
     * @param table
     * @param foodTableTemplate
     */
    public void createOrderAfterCreateTable(FoodTable table, FoodTable foodTableTemplate) {
        logger.info("after create foodTable, {}", table.getId());
        calTemplateStatusAndDiners(table, foodTableTemplate);

        //再创建订单
        OrderService orderService = OrderService.getInstance();
        logger.info("table unique code is {}", table.getUniqueCode());
        Order order = foodTableToOrder(table);
        logger.info("the order is {}", order);
        order.setOrderType(Constant.ORDER_TYPE_TANG_SHI);
        try {
            new CreateOrderChain().createOrder(order);

        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 创建相同餐桌配置的餐桌
     *
     * @param reqFoodTable
     * @throws Exception
     */
    public void syncCreateFoodTable(FoodTable reqFoodTable) throws Exception {
        FoodTableService foodTableService = FoodTableService.getInstance();
        Long sceneId = reqFoodTable.getSceneId();
        Scene scene = SceneService.getInstance().findScene(sceneId);
        Long foodTableConfigId = scene.getFoodTableConfigId();

        if (foodTableConfigId != null) {
            //再判断当前的场景值是否存在相同的餐桌配置，如果配置，那么复制一个餐桌
            List<Scene> sameFoodTableConfigSceneList = SceneService.getInstance().findSameFoodConfigList(sceneId);

            logger.info("sameFoodTableConfigSceneList is {}", StringUtils.join(sameFoodTableConfigSceneList, ","));
            //创建不同场景的餐桌
            for (Scene sameScene : sameFoodTableConfigSceneList) {
                FoodTable sameFoodTable = new FoodTable();
                BeanUtils.copyProperties(reqFoodTable, sameFoodTable, "id", "sceneId");
                sameFoodTable.setSceneId(sameScene.getId());
                logger.info("will create food table {}", sameFoodTable);
                commonService.createObject(sameFoodTable, null, false, null);

                //同步修改模板
                List<FoodTable> sameFoodTableList = foodTableService.findFoodTable(reqFoodTable.getShopId(), reqFoodTable.getRow(), reqFoodTable.getColumn(), sameScene.getId(), true);
                VerifyUtil.verify(() -> isNotEmpty(sameFoodTableList), ResponseStatus.FOOD_TABLE_NOT_EXIST);
                FoodTable sameFoodTableTemplate = sameFoodTableList.get(0);
                calTemplateStatusAndDiners(sameFoodTable, sameFoodTableTemplate);
            }
        } else {
            logger.info("scene {} food table config id is null", scene.getId());
        }
    }

    /**
     * 处理模板的状态
     *
     * @param reqFoodTable
     * @param foodTableTemplate
     */
    public void calTemplateStatusAndDiners(FoodTable reqFoodTable, FoodTable foodTableTemplate) {
        try {
            logger.info("food table template is {}", foodTableTemplate);

            //修改模板的状态
            if (reqFoodTable.getDiners() != null) {
                FoodTableConfig foodTableConfig = findFoodTableConfig(foodTableTemplate.getId());

                if (foodTableConfig == null || foodTableConfig.getMaxPerson() == null) {
                    logger.info("can not find the food table config or max person not set");
                    foodTableTemplate.setLeftPersons(null);
                    commonService.save(foodTableTemplate);
                } else {
                    int leftPersons = 0;
                    int calLeftPersons = getInt(foodTableTemplate.getLeftPersons()) - reqFoodTable.getDiners();

                    if (calLeftPersons > 0) {
                        logger.info("will set the left person to {}", leftPersons);
                        leftPersons = calLeftPersons;
                    } else {
                        logger.info("set left person to zero");
                    }

                    foodTableTemplate.setLeftPersons(leftPersons);
                    CommonService.getInstance().save(foodTableTemplate);
                }
            }

            if (foodTableTemplate.getStatus() == null ||
                    Arrays.asList(FOOD_TABLE_STATUS_EMPTY, FOOD_TABLE_STATUS_EATING).contains(foodTableTemplate.getStatus().intValue())) {
                logger.info("will set template {} status to eat", foodTableTemplate.getId());
                foodTableTemplate.setStatus(Constant.FOOD_TABLE_STATUS_EATING);
                CommonService.getInstance().save(foodTableTemplate);
            }
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 获取某一个餐桌的序列号
     *
     * @param shopId
     * @return
     */
    public Integer openFoodTable(Long shopId) throws Exception {
        return OrderNoService.getInstance().getFoodTableNo(shopId);
    }

    /**
     * 餐厅排序
     *
     * @param foodTableConfig
     */
    public void sortFoodTable(FoodTableConfig foodTableConfig) {
        getList(foodTableConfig.getRowAndColumnList()).sort(new Comparator<RowAndColumn>() {
            @Override
            public int compare(RowAndColumn o1, RowAndColumn o2) {
                //横向排序
                if (foodTableConfig.getArrangeSortType() == Constant.SORT_ROW) {
                    if (o1.getRow() > o2.getRow()) {
                        return 1;
                    } else if (o1.getRow() < o2.getRow()) {
                        return -1;
                    } else if (o1.getColumn() > o2.getColumn()) {
                        return 1;
                    } else if (o1.getColumn() < o2.getColumn()) {
                        return -1;
                    } else {
                        return 0;
                    }
                } else {
                    //纵向排序
                    if (o1.getColumn() > o2.getColumn()) {
                        return 1;
                    } else if (o1.getColumn() < o2.getColumn()) {
                        return -1;
                    } else if (o1.getRow() > o2.getRow()) {
                        return 1;
                    } else if (o1.getRow() < o2.getRow()) {
                        return -1;
                    } else return 0;
                }
            }
        });
    }

    /**
     * 查询餐桌
     *
     * @param shopId
     * @param row
     * @param column
     * @param sceneId
     */
    public List<FoodTable> findFoodTable(Long shopId, Integer row, Integer column, Long sceneId, boolean template) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setSceneId(sceneId);
        foodTable.setTemplate(template);
        foodTable.setSortField(new String[]{"createTime"});
        foodTable.setSortType("DESC");

        List<FoodTable> foodTableList = commonService.searchAll(foodTable);
        foodTableList = foodTableList.stream().sorted(Comparator.comparing(FoodTable::getCreateTime)).collect(Collectors.toList());
        return foodTableList;
    }

    /**
     * 找到唯一的一个餐桌
     *
     * @param shopId
     * @param row
     * @param column
     * @param sceneId
     * @param uniqueCode
     * @return
     */
    public FoodTable findFoodTable(Long shopId, Integer row, Integer column, Long sceneId, Integer uniqueCode) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setSceneId(sceneId);
        foodTable.setUniqueCode(uniqueCode);
        return commonService.searchOne(foodTable);
    }

    /**
     * 查询模板,同样一个餐桌会在多个场景下面
     *
     * @param shopId
     * @param row
     * @param column
     * @return
     */
    public List<FoodTable> findTemplate(Long shopId, Integer row, Integer column) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setTemplate(true);
        foodTable.setEntity(true);
        foodTable.setFlagDelete(false);
        return commonService.findLimit(foodTable, 1000);
    }

    /**
     * 查询餐桌模板
     * 相同的CODE算同一个
     *
     * @param shopId
     * @return
     */
    public List<FoodTable> findTemplate(Long shopId) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setTemplate(true);
        foodTable.setEntity(true);
        foodTable.setFlagDelete(false);

        List<FoodTable> foodTableList = commonService.findLimit(foodTable, 1000);

        List<FoodTable> filterFoodTableList = new ArrayList<>();

        for (FoodTable table : foodTableList) {
            Optional<FoodTable> foodTableOptional = filterFoodTableList.stream().filter(p -> equals(p.getCode(), table.getCode())).findFirst();
            if (!foodTableOptional.isPresent()) {
                filterFoodTableList.add(table);
            }
        }

        return filterFoodTableList;
    }

    /**
     * 查询模板
     *
     * @param shopId
     * @param row
     * @param column
     * @param sceneId
     * @return
     */
    public Optional<FoodTable> findTemplate(Long shopId, Integer row, Integer column, Long sceneId) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setSceneId(sceneId);
        foodTable.setTemplate(true);
        foodTable.setEntity(true);
        foodTable.setSortField(new String[]{"createTime"});
        foodTable.setSortType("DESC");
        return commonService.searchOneOptional(foodTable);
    }

    /**
     * 查询
     *
     * @param shopId
     * @param sceneId
     * @return
     */
    public List<FoodTable> findTemplate(Long shopId, Long sceneId) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setSceneId(sceneId);
        foodTable.setTemplate(true);
        foodTable.setEntity(true);
        return commonService.searchAll(foodTable);
    }

    /**
     * 查询餐桌
     *
     * @param foodTableId
     * @return
     * @throws Exception
     */
    public FoodTable findFoodTable(Long foodTableId) throws Exception {
        return commonService.findEntity(foodTableId, FoodTable.class);
    }

    /**
     * 通过餐桌查询相关的餐桌
     *
     * @param reqFoodTable
     * @param template
     * @return
     */
    public List<FoodTable> findFoodTable(FoodTable reqFoodTable, boolean template) throws Exception {
        VerifyUtil.verify(() -> reqFoodTable.getShopId() != null && reqFoodTable.getRow() != null && reqFoodTable.getColumn() != null && reqFoodTable.getSceneId() != null);
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(reqFoodTable.getShopId());
        foodTable.setRow(reqFoodTable.getRow());
        foodTable.setColumn(reqFoodTable.getColumn());
        foodTable.setSceneId(reqFoodTable.getSceneId());
        foodTable.setTemplate(template);
        return commonService.searchAll(foodTable);
    }

    /**
     * 查询默认的餐桌
     *
     * @param shopId
     * @param row
     * @param column
     * @return
     */
    public FoodTable findDefaultFoodTable(Long shopId, Integer row, Integer column) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setDefaultFoodTable(true);
        foodTable.setEntity(true);
        return commonService.searchOne(foodTable);
    }

    /**
     * 查询商铺下面的所有餐桌
     *
     * @param shopId
     * @return
     */
    public List<FoodTable> findDefaultFoodTable(Long shopId) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setDefaultFoodTable(true);
        return commonService.searchAll(foodTable);
    }


    /**
     * 创建默认餐桌，默认餐桌是在创建订单之后才创建的，所有一创建的时候，状态就是就餐中
     *
     * @param shopId
     * @param row
     * @param column
     */
    public FoodTable createDefaultFoodTable(Long shopId, Integer row, Integer column, Long sceneId, Integer showNo, String code) throws Exception {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setDefaultFoodTable(true);
        foodTable.setTemplate(false);
        foodTable.setUniqueCode(0);
        foodTable.setSceneId(sceneId);
        foodTable.setShowNo(showNo);
        foodTable.setCode(code);

        foodTable.setStatus(FOOD_TABLE_STATUS_EATING);
        logger.info("create default food table {}", foodTable);
        commonService.createObject(foodTable);
        return foodTable;
    }


    /**
     * 获取餐桌的KEY
     *
     * @param foodTable
     * @return
     */
    public String generateFoodTableKey(FoodTable foodTable) {
        StringBuffer stringBuffer = new StringBuffer();
        String foodTableKey = stringBuffer.append(foodTable.getRow()).append(SEPARATOR_KEY).append(foodTable.getColumn()).toString();
        return foodTableKey;
    }

    /**
     * 查询餐桌配置人数
     *
     * @param foodTableId
     * @return
     */
    public FoodTableConfig findFoodTableConfig(Long foodTableId) throws Exception {
        FoodTable foodTable = commonService.findEntity(foodTableId, FoodTable.class);
        Long sceneId = foodTable.getSceneId();
        if (sceneId == null) {
            logger.info("scene id is null");
            return null;
        }

        Scene scene = commonService.findEntity(sceneId, Scene.class);
        Long foodTableConfigId = scene.getFoodTableConfigId();
        if (foodTableConfigId == null) {
            logger.info("foodTableConfigId is null");
            return null;
        }

        FoodTableConfig foodTableConfig = commonService.findEntity(foodTableConfigId, FoodTableConfig.class);
        return foodTableConfig;
    }

    /**
     * 查询餐桌的最大人数
     *
     * @param foodTableId
     * @return
     */
    public Integer findMaxPerson(Long foodTableId) throws Exception {
        FoodTable foodTable = commonService.findEntity(foodTableId, FoodTable.class);
        Long sceneId = foodTable.getSceneId();
        if (sceneId == null) {
            logger.info("scene id is null");
            return null;
        }

        Scene scene = commonService.findEntity(sceneId, Scene.class);
        Long foodTableConfigId = scene.getFoodTableConfigId();
        if (foodTableConfigId == null) {
            logger.info("foodTableConfigId is null");
            return null;
        }

        FoodTableConfig foodTableConfig = commonService.findEntity(foodTableConfigId, FoodTableConfig.class);
        Optional<RowAndColumn> rowAndColumnOptional = foodTableConfig.getRowAndColumnList().stream().filter(rowAndColumn -> {
            return equals(foodTable.getColumn(), rowAndColumn.getColumn()) && equals(foodTable.getRow(), rowAndColumn.getRow());
        }).findAny();

        if (!rowAndColumnOptional.isPresent()) {
            logger.info("can not find the food table config {}", foodTable);
            return null;
        }

        RowAndColumn rowAndColumn = rowAndColumnOptional.get();

        logger.info("find the row and column  {}", rowAndColumn);

        return rowAndColumn.getMaxPerson();
    }

    /**
     * 通过餐桌号来准确查询
     *
     * @param shopId
     * @param foodTableKey
     * @return
     */
    public List<Order> findOrderByFoodTableKey(Long shopId, String foodTableKey) {
        try {
            Order order = new Order();
            order.setShopId(shopId);
            order.setFoodTableKey(foodTableKey);

            Shop shop = shopService.findShopById(shopId);

            //查询最近一天的
            order.setStartCreateTime(getLong(shop.getOpenTime()));
            return commonService.searchAll(order);
        } catch (Exception e) {
            logger.error("e", e);
            return new ArrayList<>();
        }
    }

    /**
     * 处理一种场景下面，模板餐桌的状态
     *
     * @param currentFoodTable
     * @param orderList
     */
    private void dealTemplateFoodTableStatus(FoodTable currentFoodTable, List<Order> orderList, Long sceneId) throws Exception {
        Long shopId = currentFoodTable.getShopId();
        Integer row = currentFoodTable.getRow();
        Integer column = currentFoodTable.getColumn();

        if (shopId == null || row == null || column == null || sceneId == null) {
            logger.info("shop id is {}, row is {}, column {} scene {}", currentFoodTable.getShopId(), currentFoodTable.getRow(), currentFoodTable.getColumn(), sceneId);
            return;
        }

        for (Order order : orderList) {
            logger.info("scene id {} , order id {} , parent order  {}, once pay end {}", sceneId, order.getId(), getBoolean(order.getParentOrder()), getBoolean(order.getOncePayEnd()));
        }

        //必须要是父订单,并且没有完成过一次完整的支付
        orderList = getList(orderList).stream().filter(order -> !getBoolean(order.getOncePayEnd()) && getBoolean(order.getParentOrder())).collect(Collectors.toList());
        logger.info("filter parent order list size is {}", orderList.size());

        boolean allEnd = false;

        if (isEmpty(orderList)) {
            allEnd = true;
        } else {
            allEnd = orderList.stream().allMatch(p -> p.getStatus() == Constant.ORDER_STATUS_END);
        }

        //是否是部分付钱
        boolean partPayed = orderList.stream().anyMatch(p -> Constant.ORDER_PART_PAY_STATUS_LIST.contains(p.getStatus()));

        //部分发送
        boolean partSend = orderList.stream().anyMatch(p -> OrderService.getInstance().isPartSend(p));

        int status = 0;

        if (allEnd) {
            logger.info("all end");
            //所有的订单均已经结束了，则将餐桌设置成空闲
            status = FOOD_TABLE_STATUS_EMPTY;
            //清空服务员
            currentFoodTable.setWaiterId(null);
            currentFoodTable.setWaiterName(null);
        } else if (partPayed) {
            //部分付款
            logger.info("part payed");
            status = FOOD_TABLE_STATUS_PART_CASH;
        } else if (partSend) {
            //部分发送
            logger.info("part send");
            status = FOOD_TABLE_STATUS_PART_SEND;
        } else {
            //就餐中
            logger.info("eating");
            status = FOOD_TABLE_STATUS_EATING;
        }

        logger.info("food table is {},  status is {}", currentFoodTable, status);

        //模板也设置成空闲
        Optional<FoodTable> templateOptional = findTemplate(currentFoodTable.getShopId(), currentFoodTable.getRow(), currentFoodTable.getColumn(), sceneId);

        if (!templateOptional.isPresent()) {
            logger.info("can not find the template for shop {} in sceneId {} row {} column {}", currentFoodTable.getShopId(), sceneId, currentFoodTable.getRow(), currentFoodTable.getColumn());
            return;
        }

        FoodTable templateFoodTable = templateOptional.get();
        logger.info("template food table is {}", templateFoodTable);
        templateFoodTable.setStatus(status);
        commonService.directSave(templateFoodTable);

        //重新设置人数 修改模板的人数
        if (allEnd) {
            logger.info("the foodTable is {} and set empty", templateFoodTable);
            templateFoodTable.setStatus(FOOD_TABLE_STATUS_EMPTY);

            Integer maxPerson = findMaxPerson(templateFoodTable.getId());
            templateFoodTable.setLeftPersons(maxPerson);

            commonService.directSave(templateFoodTable);
        } else {
            //如果不是空闲了，按照实际人数来计算人数
            //当前吃饭的总人数
            List<FoodTable> foodTableList = findFoodTable(shopId, row, column, sceneId, false);
            int dinnerTotal = foodTableList.stream().mapToInt(p -> getInt(p.getDiners())).sum();

            //查询该桌号的最大人数
            Integer maxPerson = findMaxPerson(templateFoodTable.getId());
            if (maxPerson != null) {
                logger.info("max person is {}", maxPerson);
                //有设置最大人数
                int leftPersons = Math.max(0, getInt(maxPerson - dinnerTotal));
                logger.info("max person is {}, dinner person is {}", maxPerson, dinnerTotal);
                templateFoodTable.setLeftPersons(leftPersons);
                commonService.directSave(templateFoodTable);
            } else {
                //没有找到最大人数，直接设置成空
                logger.info("can not find the food table config");
                templateFoodTable.setLeftPersons(null);
                commonService.directSave(templateFoodTable);
            }
        }
    }

    /**
     * 通过订单去查询餐厅
     *
     * @param order
     */
    public List<FoodTable> findFoodTable(Order order, boolean template) throws Exception {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(order.getShopId());
        foodTable.setRow(order.getTableRow());
        foodTable.setColumn(order.getTableColumn());
        foodTable.setTemplate(template);
        return commonService.searchAll(foodTable);
    }

    /**
     * 找餐桌
     *
     * @param shopId
     * @param uniqueCode
     * @return
     */
    public FoodTable findFoodTableByUniqueCode(Long shopId, Integer row, Integer column, Integer uniqueCode) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setUniqueCode(uniqueCode);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        return commonService.searchOne(foodTable);
    }

    /**
     * 找餐桌
     *
     * @param shopId
     * @param uniqueCode
     * @return
     */
    public FoodTable findFoodTableByUniqueCode(Long shopId, Integer uniqueCode) {
        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setUniqueCode(uniqueCode);
        return commonService.searchOne(foodTable);
    }

    /**
     * 通过订单查询所有的餐桌
     *
     * @param order
     * @return
     */
    public List<FoodTable> findFoodTableListByOrder(Order order) throws Exception {
        if (!OrderService.getInstance().isFoodTableOrder(order)) {
            logger.info("not the food table order");
            return new ArrayList<>();
        }

        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(order.getShopId());
        foodTable.setRow(order.getTableRow());
        foodTable.setColumn(order.getTableColumn());
        foodTable.setUniqueCode(order.getUniqueCode());
        foodTable.setTemplate(false);
        List<FoodTable> foodTableList = commonService.searchAll(foodTable);
        logger.info("food table list is {}", foodTableList);

        if (order.getSceneId() != null) {
            List<Scene> sameFoodConfigList = SceneService.getInstance().findSameFoodConfigList(order.getSceneId());
            Set<Long> sceneIdSet = sameFoodConfigList.stream().map(p -> p.getId()).collect(Collectors.toSet());
            sceneIdSet.add(order.getSceneId());
            return foodTableList.stream().filter(p -> p.getSceneId() != null && sceneIdSet.contains(p.getSceneId().longValue())).collect(Collectors.toList());
        } else {
            logger.info("order scene id null");
            return foodTableList;
        }
    }

    /**
     * 处理餐桌模板,统一处理，
     * 优先级如下
     * 1、存在部分结账，那么就是部分结账。
     * 2、存在部分发送，那么就是部分发送。
     * 3、存在就餐中，那么就是就餐中。
     * 4、什么订单都没有，就是空台，已结账。
     * 5、如果订单都已经发送到厨房了，那么就是就餐中。
     * <p>
     * <p>
     * 1、如果是默认餐桌，那么所有场景均需要处理。
     * 2、如果是uniqueCode不为0的餐桌，那么只需要处理对应场景的餐桌模板
     *
     * @param reqFoodTable
     * @throws Exception
     */
    public void dealTemplateFoodTable(FoodTable reqFoodTable) throws Exception {
        if (reqFoodTable == null) {
            logger.error("food table is null");
            return;
        }

        //如果没有横纵坐标也返回
        if (reqFoodTable.getRow() == null || reqFoodTable.getColumn() == null) {
            logger.error("row or column is empty");
            return;
        }

        //处理对应场景的餐桌模板
        logger.info("will deal template food table");
        realDealTemplateFoodTable(reqFoodTable);
    }

    /**
     * 处理餐桌的模板状态  在删除桌子，或者是付款的时候调用
     * <p>
     * 如果先付款状态下开启了，桌面状态就是空桌/已结账，未付款，已部分结账，已部分发送。付款就变空了，这个没有关系。
     * <p>
     * 未付款的状态就是服务员这边点餐了 但是没有结账 或者是c端下单了 没有结账。如果是c端下单了没有结账，b端是可以看到且可以操作的。
     */
    private void realDealTemplateFoodTable(FoodTable reqFoodTable) throws Exception {
        Long shopId = reqFoodTable.getShopId();
        Integer row = reqFoodTable.getRow();
        Integer column = reqFoodTable.getColumn();
        Long sceneId = reqFoodTable.getSceneId();

        if (shopId == null || row == null || column == null || sceneId == null) {
            logger.error("shop is {}, row {} column {}, sceneId {}, food table {}", shopId, row, column, sceneId, reqFoodTable);
            return;
        }

        List<Scene> sceneList = SceneService.getInstance().foodTableMatchSceneList(reqFoodTable);
        List<Long> sceneIdList = sceneList.stream().map(p -> p.getId()).collect(Collectors.toList());

        logger.info("scene id list is {}", StringUtils.join(sceneIdList, ","));
        //通过food table key查询所有的订单出来,这里是模糊匹配，也就是说不匹配unicode值，只匹配row and column
        List<Order> orderList = OrderService.getInstance().findOrderListByTemplateKey(reqFoodTable.getShopId(), generateFoodTableKey(reqFoodTable), sceneId);
        List<Long> orderIdList = orderList.stream().map(o -> o.getId()).collect(Collectors.toList());
        logger.info("order list size is {}, and will filter scene {}, and order id list is {}", orderList.size(), sceneId, StringUtils.join(orderIdList, ","));

        //由于是通过food table key查询出来的，那么可能会查询出不同场景下面的订单出来，只处理同一个餐桌配置的订单，来决定最后的状态
        orderList = orderList.stream().filter(p -> sceneIdList.contains(p.getSceneId().longValue())).collect(Collectors.toList());
        logger.info("after filter order list size is {}", orderList.size());

        //过滤出开店到当前时间的订单
        Shop shop = ShopService.getInstance().findShopById(shopId);
        orderList = orderList.stream().filter(p -> p.getCreateTime() != null && p.getCreateTime() >= shop.getOpenTime()).collect(Collectors.toList());
        logger.info("after filter time order list size is {}", orderList.size());

        //所有的相同餐桌配置的餐桌模板均处理一遍
        Set<Long> sceneIdSet = new HashSet<>(sceneIdList);
        sceneIdSet.add(sceneId);

        for (Long perSceneId : sceneIdSet) {
            dealTemplateFoodTableStatus(reqFoodTable, orderList, perSceneId);
        }
    }

    /**
     * 将餐桌转化成订单
     *
     * @param foodTable
     * @return
     */
    public Order foodTableToOrder(FoodTable foodTable) {
        Order order = new Order();
        order.setShopId(foodTable.getShopId());
        order.setTableRow(foodTable.getRow());
        order.setTableColumn(foodTable.getColumn());
        order.setUniqueCode(foodTable.getUniqueCode());
        order.setCode(foodTable.getCode());
        order.setSceneId(foodTable.getSceneId());
        order.setPersons(foodTable.getDiners());
        return order;
    }

    /**
     * 创建商铺的订单号
     *
     * @param shopId
     * @return
     */
    public Integer createFoodTableNo(Long shopId, Integer row, Integer column, Long sceneId) throws Exception {
        logger.info("create food table no shopId {}, row {}, column {}， sceneId {}", shopId, row, column, sceneId);
        Shop shop = shopService.findShopById(shopId);

        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(shopId);
        foodTable.setRow(row);
        foodTable.setColumn(column);
        foodTable.setSceneId(sceneId);
        foodTable.setTemplate(false);
        foodTable.setStartCreateTime(shop.getOpenTime());
        List<FoodTable> foodTableList = commonService.searchAll(foodTable);

        //如果为空时，默认从2开始
        if (isEmpty(foodTableList)) {
            logger.info("food table list is empty");
            return null;
        }

        //只有一个餐桌,那么加上当前的餐桌，就是2号
        if (foodTableList.size() == 1) {
            FoodTable foodTableInDb = foodTableList.get(0);
            if (foodTableInDb.getShowNo() == null) {
                logger.info("only one food table , and no is empty, will return show no 2");
                return 2;
            } else {
                logger.info("only one food table, but has the show no, will return show no null");
                return null;
            }
        }

        //如果存在，则取最大值
        OptionalInt max = foodTableList.stream().mapToInt(p -> getInt(p.getShowNo())).max();
        if (max.isPresent()) {
            logger.info("max number is {}", max.getAsInt());
            return Math.max(max.getAsInt() + 1, 2);
        } else {
            logger.info("food table list is more than one , but noBody has show no {}, will return show no 2");
            return 2;
        }
    }

    /**
     * 清理餐桌
     *
     * @param foodTable
     */
    public void cleanFoodTable(FoodTable foodTable) throws Exception {
        //不是固定餐桌，那么删除
        if (getInt(foodTable.getUniqueCode()) != 0) {
            commonService.delete(foodTable);
        } else {
            //固定餐桌，那么只是清理参数
            foodTable.setDiners(null);
            foodTable.setWaiterName(null);
            foodTable.setWaiterId(null);
            commonService.save(foodTable);
        }
    }

    /**
     * 通过订单来查询餐桌
     *
     * @param order
     * @return
     */
    public FoodTable findFoodTable(Order order) {
        if (order == null) {
            logger.info("order is null");
            return null;
        }

        if (order.getTableRow() == null || order.getTableColumn() == null) {
            logger.info("row is null or column is null");
            return null;
        }

        FoodTable foodTable = new FoodTable();
        foodTable.setShopId(order.getShopId());
        foodTable.setUniqueCode(order.getUniqueCode());
        foodTable.setRow(order.getTableRow());
        foodTable.setColumn(order.getTableColumn());
        return commonService.searchOne(foodTable);
    }

    /**
     * 配置到餐桌的同步
     * <p>
     * <p>
     * 如果场景对应的餐桌不存在，那么创建
     *
     * @param foodTableConfig
     */
    public void configToSceneFoodTable(FoodTableConfig foodTableConfig) throws Exception {
        if (foodTableConfig.getId() == null) {
            logger.info("config id is null");
            return;
        }

        //一定要是数据库里面的
        FoodTableConfig foodTableConfigInDb = commonService.findEntity(foodTableConfig.getId(), FoodTableConfig.class);

        List<Long> sceneList = SceneService.getInstance().findSceneByFoodTableConfig(foodTableConfig.getId()).stream().map(p -> p.getId()).collect(Collectors.toList());

        if (isEmpty(sceneList)) {
            logger.info("scene {} list is empty", foodTableConfig.getId());
            return;
        }

        for (Long sceneId : sceneList) {
            syncFoodTableConfigToScene(foodTableConfigInDb, sceneId);
        }
    }

    /**
     * 同步餐桌配置到场景
     *
     * @param foodTableConfigInDb
     * @param sceneId
     * @throws Exception
     */
    public void syncFoodTableConfigToScene(FoodTableConfig foodTableConfigInDb, Long sceneId) throws Exception {
        List<RowAndColumn> existRowAndColumnList = getList(foodTableConfigInDb.getRowAndColumnList());
        List<FoodTable> templateFoodTableList = findTemplate(foodTableConfigInDb.getShopId(), sceneId);

        //存在，并且code是一样的，不处理
        for (FoodTable foodTable : templateFoodTableList) {
            Optional<RowAndColumn> rowAndColumnOptional = findRowAndColumn(foodTable, existRowAndColumnList);

            //餐桌没有在坐标列表里面，删除删除餐桌
            if (!rowAndColumnOptional.isPresent()) {
                foodTable.setFlagDelete(true);
                commonService.save(foodTable);
                logger.info("will delete food table {}", foodTable.getId());
                continue;
            }

            RowAndColumn rowAndColumn = rowAndColumnOptional.get();

            //找到了一样的坐标，再判断code是否一样，如果code一样，则不用处理
            if (equals(rowAndColumn.getCode(), foodTable.getCode())) {
                logger.info("code equals for code {}", foodTable.getCode());
                continue;
            }

            //不一样的code，需要更新
            foodTable.setCode(rowAndColumn.getCode());

            //大于0的时候才同步
            if (getInt(rowAndColumn.getMaxPerson()) > 0) {
                foodTable.setLeftPersons(rowAndColumn.getMaxPerson());
            }

            commonService.save(foodTable);
        }

        //如果是坐标系统里面有的，但是餐桌没有的，则创建
        for (RowAndColumn rowAndColumn : existRowAndColumnList) {
            List<FoodTable> foodTableList = findFoodTable(rowAndColumn, templateFoodTableList);

            if (isNotEmpty(foodTableList)) {
                //如果有多条，删除多的数据，只剩下一条数据
                logger.info("row {} column {} exist , will update type code to {} code to {} , and left person is {}",
                        rowAndColumn.getRow(), rowAndColumn.getColumn(), foodTableConfigInDb.getCode(), rowAndColumn.getCode(), foodTableConfigInDb.getMaxPerson());

                FoodTable foodTable = foodTableList.get(0);
                foodTable.setCode(rowAndColumn.getCode());
                foodTable.setTypeCode(foodTableConfigInDb.getCode());

                if (getInt(rowAndColumn.getMaxPerson()) > 0) {
                    foodTable.setLeftPersons(rowAndColumn.getMaxPerson());
                }

                commonService.save(foodTable);

                //剩下的数据删除
                for (FoodTable table : foodTableList.stream().filter(p -> !equals(p.getId(), foodTable.getId())).collect(Collectors.toList())) {
                    table.setFlagDelete(true);
                    commonService.save(table);
                    logger.info("will delete food table {}", table.getId());
                }

                continue;
            }

            //不存在，则创建
            FoodTable createFoodTable = new FoodTable();
            createFoodTable.setTemplate(true);
            createFoodTable.setRow(rowAndColumn.getRow());
            createFoodTable.setColumn(rowAndColumn.getColumn());
            createFoodTable.setCode(rowAndColumn.getCode());
            createFoodTable.setTypeCode(foodTableConfigInDb.getCode());
            createFoodTable.setShopId(foodTableConfigInDb.getShopId());

            if (getInt(rowAndColumn.getMaxPerson()) > 0) {
                createFoodTable.setLeftPersons(rowAndColumn.getMaxPerson());
            }

            createFoodTable.setStatus(Constant.FOOD_TABLE_STATUS_EMPTY);
            createFoodTable.setSceneId(sceneId);
            logger.info("create food table is {}", createFoodTable);
            //创建模板
            commonService.createObject(createFoodTable);
        }
    }

    /**
     * @param rowAndColumn
     * @param rowAndColumnList
     * @return
     */
    public Optional<RowAndColumn> findRowAndColumn(RowAndColumn rowAndColumn, List<RowAndColumn> rowAndColumnList) {
        return rowAndColumnList.stream().filter(p -> getInt(p.getRow()) == getInt(rowAndColumn.getRow()) && getInt(p.getColumn()) == getInt(rowAndColumn.getColumn())).findAny();
    }

    /**
     * 判断餐桌在不在配置里面
     *
     * @param foodTable
     * @param rowAndColumnList
     * @return
     */
    public Optional<RowAndColumn> findRowAndColumn(FoodTable foodTable, List<RowAndColumn> rowAndColumnList) {
        return rowAndColumnList.stream().filter(p -> getInt(p.getRow()) == getInt(foodTable.getRow()) && getInt(p.getColumn()) == getInt(foodTable.getColumn())).findAny();
    }

    /**
     * 在餐桌里面查询坐标
     *
     * @param rowAndColumn
     * @param foodTableList
     * @return
     */
    public List<FoodTable> findFoodTable(RowAndColumn rowAndColumn, List<FoodTable> foodTableList) {
        return foodTableList.stream().filter(f -> getInt(f.getRow()) == getInt(rowAndColumn.getRow()) && getInt(f.getColumn()) == getInt(rowAndColumn.getColumn())).collect(Collectors.toList());
    }

    /**
     * 处理订单上面的餐桌状态
     * 有可能会有多个场景，那么多个场景下面的餐桌依次处理，并且会处理模板餐桌的状态
     *
     * @param order
     * @throws Exception
     */
    public void dealOrderFoodTableStatus(Order order) throws Exception {
        List<FoodTable> foodTableList = findFoodTableListByOrder(order);
        for (FoodTable foodTable : foodTableList) {
            //如果全部已经发送了，那么改成就餐中
            //修改餐桌状态
            if (OrderService.getInstance().isOrderPartPay(order)) {
                logger.info("current table status is part pay");
                foodTable.setStatus(FOOD_TABLE_STATUS_PART_CASH);
            } else if (OrderService.getInstance().isAllSendPrint(order)) {
                logger.info("current table status is all print");
                foodTable.setStatus(FOOD_TABLE_STATUS_EATING);
            } else if (OrderService.getInstance().isPartSend(order)) {
                logger.info("current table status is part send to kitchen");
                foodTable.setStatus(FOOD_TABLE_STATUS_PART_SEND);
            } else {
                logger.info("current table status is eating");
                foodTable.setStatus(FOOD_TABLE_STATUS_EATING);
            }

            //如果订单已经发送了，那么餐桌也修改成已发送
            if (isNotEmpty(order.getSendPrinterList())) {
                logger.info("set food table {}  to send", foodTable.getId());
                foodTable.setSendPrinter(true);
            } else {
                //如果没有发送，那么设置成false
                foodTable.setSendPrinter(false);
            }

            commonService.directSave(foodTable);

            //处理模板
            dealTemplateFoodTable(foodTable);
        }
    }

    /**
     * 将餐桌同步到其它场景下面
     *
     * @param foodTable
     */
    public void syncToOtherSceneFoodConfig(FoodTable foodTable) throws Exception {
        Long foodTableId = foodTable.getId();

        if (foodTableId == null) {
            logger.info("foodTableIds is null");
            return;
        }

        FoodTable foodTableInDb = findFoodTable(foodTableId);
        List<FoodTable> sameConfigTableList = findSameConfigTable(foodTableInDb);
        for (FoodTable table : sameConfigTableList) {
            logger.info("sync to id {}", table.getId());
            BeanUtils.copyProperties(foodTableInDb, table, "id", "sceneId");
            commonService.save(table);
        }
    }

    /**
     * 查询相同KEY，并且是相同餐桌配置，但是只是场景不一样
     *
     * @param foodTable
     * @return
     */
    public List<FoodTable> findSameConfigTable(FoodTable foodTable) throws Exception {
        if (foodTable == null) {
            logger.info("foodTable is null");
            return new ArrayList<>();
        }

        if (foodTable.getShopId() == null) {
            logger.info("shop id is null");
            return new ArrayList<>();
        }

        if (foodTable.getSceneId() == null) {
            logger.info("scene id is null");
            return new ArrayList<>();
        }

        if (foodTable.getColumn() == null || foodTable.getRow() == null) {
            logger.info("column is {}, row is {}", foodTable.getColumn(), foodTable.getRow());
            return new ArrayList<>();
        }

        Long sceneId = foodTable.getSceneId();
        List<Scene> sameFoodConfigList = SceneService.getInstance().findSameFoodConfigList(sceneId);

        if (isEmpty(sameFoodConfigList)) {
            logger.info("sameFoodConfigList is null");
            return new ArrayList<>();
        }

        List<Long> sameFoodTableConfigIdList = sameFoodConfigList.stream().map(p -> p.getId()).collect(Collectors.toList());

        FoodTable foodTableReq = new FoodTable();
        foodTableReq.setShopId(foodTable.getShopId());
        foodTableReq.setRow(foodTable.getRow());
        foodTableReq.setColumn(foodTable.getColumn());
        foodTableReq.setEntity(true);
        foodTableReq.setUniqueCode(foodTable.getUniqueCode());

        //位置相同的餐桌，还必须要是相同的餐桌配置
        return commonService.searchAll(foodTableReq).stream().filter(f -> {
            return sameFoodTableConfigIdList.contains(f.getSceneId().longValue());
        }).collect(Collectors.toList());
    }


}
